【修改】oauth2.0 密码模式认证

This commit is contained in:
wangiegie@gmail.com 2017-10-27 10:53:38 +08:00
parent 3c80d8272f
commit a5e405ccce
19 changed files with 298 additions and 323 deletions

View File

@ -0,0 +1,16 @@
package com.github.pig.config.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author lengleng
* @date 2017/10/26
*/
@RestController
public class DemoController {
@GetMapping("/demo")
public String demo() {
return "demo method success";
}
}

View File

@ -23,8 +23,5 @@ eureka:
prefer-ip-address: true
client:
serviceUrl:
defaultZone: http://eureka.didispace.com/eureka/
#关闭安全校验
management:
security:
enabled: false
defaultZone: http://127.0.0.1:9000/eureka/

View File

@ -0,0 +1,33 @@
package com.github.pig.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.security.Principal;
@SpringBootApplication
@RestController
@EnableAuthorizationServer
@EnableResourceServer
public class AuthserverApplication {
@RequestMapping("/user")
public Principal user(Principal user) {
return user;
}
@GetMapping("/test")
public String test() {
return "test";
}
public static void main(String[] args) {
SpringApplication.run(AuthserverApplication.class, args);
}
}

View File

@ -9,3 +9,8 @@ eureka:
client:
fetch-registry: false
register-with-eureka: false
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
instance:
hostname: localhost

View File

@ -23,7 +23,7 @@ eureka:
prefer-ip-address: true
client:
serviceUrl:
defaultZone: http://eureka.didispace.com/eureka/
defaultZone: http://127.0.0.1:9000/eureka/
#关闭安全校验
management:

View File

@ -18,16 +18,26 @@
</parent>
<dependencies>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.7.0</version>
</dependency>
<!--消息总线-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<!--Redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--oauth2.0-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.7.0</version>
</dependency>
</dependencies>

View File

@ -3,6 +3,7 @@ package com.github.pig.auth;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
/**
* @author lengleng
@ -14,4 +15,7 @@ public class PigServiceAuthApplication {
public static void main(String[] args) {
SpringApplication.run(PigServiceAuthApplication.class, args);
}
}

View File

@ -0,0 +1,56 @@
package com.github.pig.auth.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
/**
* @author lengleng
* @date 2017/10/26
* 认证服务器配置
*/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private RedisConnectionFactory redisConnectionFactory;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService)
.tokenStore(new RedisTokenStore(redisConnectionFactory));
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("lengleng")
.secret("lengleng")
.authorizedGrantTypes("authorization_code", "refresh_token", "password")
.scopes("ui");
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
}

View File

@ -0,0 +1,13 @@
package com.github.pig.auth.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
/**
* @author lengleng
* @date 2017/10/26
*/
@Configuration
@EnableResourceServer
public class PigResoureServerConfig {
}

View File

@ -0,0 +1,58 @@
package com.github.pig.auth.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* @author lengleng
* @date 2017/10/26
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class PigWebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(new PasswordEncoder() {
@Override
public String encode(CharSequence charSequence) {
return charSequence.toString();
}
@Override
public boolean matches(CharSequence charSequence, String s) {
return s.equals(charSequence.toString());
}
});
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.anonymous().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.csrf().disable();
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}

View File

@ -1,64 +0,0 @@
package com.github.pig.auth.controller;
import com.github.pig.auth.service.AuthService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
/**
* @author lengleng
* @date 2017/10/13
*/
@RestController
@RefreshScope
public class AuthController {
@Value("${jwt.token.header}")
private String tokenHeader;
@Autowired
private AuthService authService;
@RequestMapping(value = "token", method = RequestMethod.POST)
public ResponseEntity<?> createAuthenticationToken(
String username, String password) throws Exception {
final String token = authService.login(username, password);
return ResponseEntity.ok(token);
}
@RequestMapping(value = "refresh", method = RequestMethod.GET)
public ResponseEntity<?> refreshAndGetAuthenticationToken(
HttpServletRequest request) {
String token = request.getHeader(tokenHeader);
String refreshedToken = authService.refresh(token);
if (refreshedToken == null) {
return ResponseEntity.badRequest().body(null);
} else {
return ResponseEntity.ok(refreshedToken);
}
}
@RequestMapping(value = "verify", method = RequestMethod.GET)
public ResponseEntity<?> verify(String token) throws Exception {
authService.validate(token);
return ResponseEntity.ok(true);
}
@RequestMapping(value = "invalid", method = RequestMethod.POST)
public ResponseEntity<?> invalid(@RequestHeader("access-token") String token) {
authService.invalid(token);
return ResponseEntity.ok(true);
}
@RequestMapping(value = "user", method = RequestMethod.GET)
public String getUserInfo(String token) throws Exception {
String username = authService.getUserNameByToken(token);
return tokenHeader;
}
}

View File

@ -0,0 +1,20 @@
package com.github.pig.auth.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.security.Principal;
/**
* @author lengleng
* @date 2017/10/26
*/
@RestController
public class UserController {
@GetMapping("/user")
public Object user(Principal user) {
return user;
}
}

View File

@ -0,0 +1,62 @@
package com.github.pig.auth.serivce;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* @author lengleng
* @date 2017/10/26
*/
@Service
public class UserDetailServiceImpl implements UserDetailsService, Serializable {
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
return new UserDetails() {
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
GrantedAuthority grantedAuthority = (GrantedAuthority) () -> "admin";
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
grantedAuthorities.add(grantedAuthority);
return grantedAuthorities;
}
@Override
public String getPassword() {
return "admin";
}
@Override
public String getUsername() {
return "admin";
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
};
}
}

View File

@ -1,48 +0,0 @@
package com.github.pig.auth.service;
/**
* @author lengleng
*/
public interface AuthService {
/**
* 用户登录
*
* @param username 用户名
* @param password 密码
* @return token
* @throws Exception Exception
*/
String login(String username, String password) throws Exception;
/**
* 刷新token
*
* @param oldToken 旧的token
* @return 新token
*/
String refresh(String oldToken);
/**
* 校验token
*
* @param token token
* @throws Exception Exception
*/
void validate(String token) throws Exception;
/**
* token置为失效
*
* @param token token
* @return
*/
Boolean invalid(String token);
/**
* 通过token换取用户名
*
* @param token token
* @return 用户名
*/
String getUserNameByToken(String token);
}

View File

@ -1,33 +0,0 @@
package com.github.pig.auth.service;
import java.util.List;
/**
* @author lengleng
*/
public interface ClientService {
/**
* client信息获取token
*
* @param clientId clientId
* @param secret secret
* @return token
* @throws Exception Exception
*/
String apply(String clientId, String secret) throws Exception;
/**
* 获取授权的客户端列表
*
* @param serviceId serviceId
* @param secret secret
* @return 客户端列表
*/
List<String> getAllowedClient(String serviceId, String secret);
/**
* 注册客户端
*/
void registryClient();
}

View File

@ -1,123 +0,0 @@
package com.github.pig.auth.service;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* @author lengleng
* @date 2017/10/13
*/
@Component
public class JwtTokenUtil implements Serializable {
private static final long serialVersionUID = -3301605591108950415L;
private static final String CLAIM_KEY_USERNAME = "sub";
private static final String CLAIM_KEY_CREATED = "created";
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.expiration}")
private Long expiration;
public String getUsernameFromToken(String token) {
String username;
try {
final Claims claims = getClaimsFromToken(token);
username = claims.getSubject();
} catch (Exception e) {
username = null;
}
return username;
}
public Date getCreatedDateFromToken(String token) {
Date created;
try {
final Claims claims = getClaimsFromToken(token);
created = new Date((Long) claims.get(CLAIM_KEY_CREATED));
} catch (Exception e) {
created = null;
}
return created;
}
public Date getExpirationDateFromToken(String token) {
Date expiration;
try {
final Claims claims = getClaimsFromToken(token);
expiration = claims.getExpiration();
} catch (Exception e) {
expiration = null;
}
return expiration;
}
private Claims getClaimsFromToken(String token) {
Claims claims;
try {
claims = Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
} catch (Exception e) {
claims = null;
}
return claims;
}
private Date generateExpirationDate() {
return new Date(System.currentTimeMillis() + expiration * 1000);
}
private Boolean isTokenExpired(String token) {
final Date expiration = getExpirationDateFromToken(token);
return expiration.before(new Date());
}
private Boolean isCreatedBeforeLastPasswordReset(Date created, Date lastPasswordReset) {
return (lastPasswordReset != null && created.before(lastPasswordReset));
}
public String generateToken(String username) {
Map<String, Object> claims = new HashMap<>(2);
claims.put(CLAIM_KEY_USERNAME, username);
claims.put(CLAIM_KEY_CREATED, new Date());
return generateToken(claims);
}
String generateToken(Map<String, Object> claims) {
return Jwts.builder()
.setClaims(claims)
.setExpiration(generateExpirationDate())
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
public Boolean canTokenBeRefreshed(String token, Date lastPasswordReset) {
final Date created = getCreatedDateFromToken(token);
return !isCreatedBeforeLastPasswordReset(created, lastPasswordReset)
&& !isTokenExpired(token);
}
public String refreshToken(String token) {
String refreshedToken;
try {
final Claims claims = getClaimsFromToken(token);
claims.put(CLAIM_KEY_CREATED, new Date());
refreshedToken = generateToken(claims);
} catch (Exception e) {
refreshedToken = null;
}
return refreshedToken;
}
}

View File

@ -1,39 +0,0 @@
package com.github.pig.auth.service.impl;
import com.github.pig.auth.service.AuthService;
import com.github.pig.auth.service.JwtTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author lengleng
*/
@Service
public class AuthServiceImpl implements AuthService {
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Override
public String login(String username, String password) throws Exception {
return jwtTokenUtil.generateToken(username);
}
@Override
public void validate(String token) throws Exception {
}
@Override
public Boolean invalid(String token) {
return null;
}
@Override
public String refresh(String oldToken) {
return null;
}
@Override
public String getUserNameByToken(String token) {
return jwtTokenUtil.getUsernameFromToken(token);
}
}

View File

@ -22,9 +22,16 @@ eureka:
prefer-ip-address: true
client:
serviceUrl:
defaultZone: http://eureka.didispace.com/eureka/
defaultZone: http://127.0.0.1:9000/eureka/
security:
user:
password: lengleng
name: lengleng
oauth2:
client:
client-secret: lengleng
clientId: lengleng
authorized-grant-types: password
scope: openid
#关闭安全校验
management:
security:
enabled: false

View File

@ -48,6 +48,7 @@
<module>pig-config</module>
<module>pig-gateway</module>
<module>pig-service-auth</module>
<module>pig-demo-service</module>
</modules>
<dependencyManagement>