网上有很多该系列的教程,但是很多都是
spring boot1.x,
很少看见关于spring boot 2.0
.本人是打算做个spring cloud的web程序,这个整合我就是放在zuul上,类似于做了个网关的鉴权吧。。
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.0.4.RELEASEversion>
<relativePath/>
parent>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<java.version>1.8java.version>
<spring.druid.version>1.1.10spring.druid.version>
<spring.mybatis.version>1.3.2spring.mybatis.version>
<mapper.spring.version>2.0.4mapper.spring.version>
<pagehelper.spring.version>1.2.6pagehelper.spring.version>
<jwt.verson>0.9.0jwt.verson>
properties>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-securityartifactId>
dependency>
<dependency>
<groupId>org.springframework.security.oauthgroupId>
<artifactId>spring-security-oauth2artifactId>
dependency>
<dependency>
<groupId>org.springframework.securitygroupId>
<artifactId>spring-security-jwtartifactId>
dependency>
<dependency>
<groupId>org.springframework.security.oauth.bootgroupId>
<artifactId>spring-security-oauth2-autoconfigureartifactId>
dependency>
<dependency>
<groupId>io.jsonwebtokengroupId>
<artifactId>jjwtartifactId>
<version>${jwt.verson}version>
dependency>
@Component
@Slf4j
public class AppUserDetailsService implements UserDetailsService {
@Autowired
private PasswordEncoder passwordEncoder;
/**
* 表单登录
*/
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
return buildUser(userName);
}
//用户必须要有ROLE_USER 才可以登录 服务提供商
private UserDetails buildUser(String userId) {
// 根据用户名查找用户信息,这里可以写我们的登录逻辑比如说XXXXservice.findUser(String user);
//根据查找到的用户信息判断用户是否被冻结
String password = passwordEncoder.encode("123456");
log.info("数据库密码是:"+password);
return new User(userId, password,
true, true, true, true,
AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_ADMIN,ROLE_USER"));
}
}
@EnableResourceServer
@Configuration
@EnableResourceServer
public class AppWebSecurityConfigurerAdapter extends ResourceServerConfigurerAdapter {
private final AppSecurityExpressionHandler appSecurityExpressionHandler;
private final ZuulProperties zuulProperties;
private final AuthenticationSuccessHandler appAuthenticationSuccessHandler;
private final AuthenticationFailureHandler appAuthenticationFailureHandler;
private final AccessDeniedHandler appAccessDeniedHandler;
public AppWebSecurityConfigurerAdapter(AppSecurityExpressionHandler appSecurityExpressionHandler, ZuulProperties zuulProperties, AuthenticationSuccessHandler appAuthenticationSuccessHandler, AuthenticationFailureHandler appAuthenticationFailureHandler, AccessDeniedHandler appAccessDeniedHandler) {
this.appSecurityExpressionHandler = appSecurityExpressionHandler;
this.zuulProperties = zuulProperties;
this.appAuthenticationSuccessHandler = appAuthenticationSuccessHandler;
this.appAuthenticationFailureHandler = appAuthenticationFailureHandler;
this.appAccessDeniedHandler = appAccessDeniedHandler;
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.formLogin()
//登录失败过滤器
.failureHandler(appAuthenticationFailureHandler)
//配置登录成功过滤器
.successHandler(appAuthenticationSuccessHandler)
//配置登录地址
.loginPage(ZuulAppConstant.LOGIN_URL)
//配置未登录跳转URL
.loginProcessingUrl(ZuulAppConstant.LOGIN_JUMP_CONTROLLER)
//配置get不需要验证的URL
.and()
.authorizeRequests()
.antMatchers(HttpMethod.GET,zuulProperties.getAuth().toGetAdapter())
.permitAll()
//配置post不需要验证的URL
.and()
.authorizeRequests()
.antMatchers(HttpMethod.POST,zuulProperties.getAuth().toPostAdapter())
.permitAll()
//除上述URL,都需要登录用户
.and()
.authorizeRequests()
.anyRequest()
.authenticated()
//配置用户无权限登录过滤器
.and()
.exceptionHandling().accessDeniedHandler(appAccessDeniedHandler)
.and()
.csrf().disable()
.authorizeRequests()
.anyRequest()
//配置授权验证服务
.access("@defaultZuulAuthorizationService.hasPermission(request,authentication)");
}
//和鉴权服务有关,springboot2.0新加入部分
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
// TODO Auto-generated method stub
resources.expressionHandler(appSecurityExpressionHandler);
}
}
@EnableWebSecurity
@Order(6)
public class AppSecurityConfigurer extends WebSecurityConfigurerAdapter {
@Override
@Bean
//spring boot 新加的
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
/**
* 认证成功跳转
* @author w4837
*
*/
@Component(value = "AppAuthenticationSuccessHandler")
@Slf4j
public class AppAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
@Autowired
private ObjectMapper objectMapper;
@Autowired
private ClientDetailsService clientDetailsService;
@Override
@Order
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse, Authentication authentication)
throws IOException, ServletException {
log.info("登陆成功");
}
}
###配置登录失败过滤器
@Slf4j
@Component("AppAuthenticationFailureHandler")
public class AppAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler{
@Autowired
private ObjectMapper objectMapper;
@Override
public void onAuthenticationFailure(HttpServletRequest request
, HttpServletResponse response, AuthenticationException exception)
throws IOException, ServletException {
log.info("登录失败");
super.onAuthenticationFailure(request, response, exception);
}
}
@Component("AppAccessDeniedHandler")
public class AppAccessDeniedHandler implements AccessDeniedHandler{
@Autowired
private ObjectMapper objectMapper;
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.setContentType(ZuulAppConstant.CONTENT_TYPE_JSON);
response.setStatus(HttpStatus.SC_FORBIDDEN);
response.getWriter().write(objectMapper.writeValueAsString(ResultVo.createErrorResult("当前用户访问权限不够,请联系管理员增加对应权限",403)));
}
}
@Configuration("appSecurityExpressionHandler")
public class AppSecurityExpressionHandler extends OAuth2WebSecurityExpressionHandler{
@Bean
public OAuth2WebSecurityExpressionHandler oAuth2WebSecurityExpressionHandler(ApplicationContext applicationContext) {
OAuth2WebSecurityExpressionHandler expressionHandler = new OAuth2WebSecurityExpressionHandler();
expressionHandler.setApplicationContext(applicationContext);
return expressionHandler;
}
}
/**
* Copyright © 2018 eSunny Info. Tech Ltd. All rights reserved.
*
* @author [email protected]
* @program: app-management
* @title:ZuulAuthorizationService
* @Package com.yulece.app.management.zuul.authorization.service
* @Description:
* @Date 创建时间 2018/9/30-18:23
**/
public interface ZuulAuthorizationService {
/**
* 验证用户是否有权登录
* @param request
* @param authentication
* @return
*/
boolean hasPermission(HttpServletRequest request , Authentication authentication);
}
/**
* Copyright © 2018 eSunny Info. Tech Ltd. All rights reserved.
*
* @author [email protected]
* @program: app-management
* @title:DefaultRbacService
* @Package com.yulece.app.management.zuul.authorization.service
* @Description:
* @Date 创建时间 2018/9/30-18:58
**/
@Component("defaultZuulAuthorizationService")
public class DefaultZuulAuthorizationService implements ZuulAuthorizationService {
private final static Logger LOGGER = LoggerFactory.getLogger(DefaultZuulAuthorizationService.class);
private AntPathMatcher antPathMatcher = new AntPathMatcher();
@Override
public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
boolean isPermission = false;
String requestURI = request.getRequestURI();
if(StringUtils.isEmpty(requestURI)){
return isPermission;
}
//匿名用户不能经过授权
if(authentication!=null&&!authentication.getPrincipal().equals("anonymousUser")&&
authentication.isAuthenticated()) {
String userName = (String)authentication.getPrincipal();
//读取用户所有的Url,可以通过用户服务拿到当前用户服务拿到该用户的能访问的地址
Set<String> urls = new HashSet<>();
urls.add("/app/**");
for (String url : urls) {
if (antPathMatcher.match(url, requestURI)) {
isPermission = true;
LOGGER.info("用户[{}]鉴权,鉴权地址为:{}.",userName,requestURI);
break;
}
}
return isPermission;
}
return isPermission;
}
}
@ConfigurationProperties(prefix = "app.zuul")
public class ZuulProperties{
private AuthProperties auth = new AuthProperties();
private OAuth2Properties oauth = new OAuth2Properties();
public OAuth2Properties getOauth() {
return oauth;
}
public void setOauth(OAuth2Properties oauth) {
this.oauth = oauth;
}
public AuthProperties getAuth() {
return auth;
}
public void setAuth(AuthProperties auth) {
this.auth = auth;
}
}
public class AuthProperties {
private List<String> methodGetUrl = Lists.newArrayList();
private List<String> methodPostUrl = Lists.newArrayList("hello");
public List<String> getMethodGetUrl() {
return methodGetUrl;
}
public void setMethodGetUrl(List<String> methodGetUrl) {
this.methodGetUrl = methodGetUrl;
}
public List<String> getMethodPostUrl() {
return methodPostUrl;
}
public void setMethodPostUrl(List<String> methodPostUrl) {
this.methodPostUrl = methodPostUrl;
}
public String[] toGetAdapter(){
if(methodGetUrl.size() > 0 ){
String[] toBeStored = methodGetUrl.toArray(new String[methodGetUrl.size()]);
return toBeStored;
}
return new String[]{""};
}
public String[] toPostAdapter(){
if(methodPostUrl.size() > 0 ){
String[] toBeStored = methodPostUrl.toArray(new String[methodPostUrl.size()]);
return toBeStored;
}
return new String[]{""};
}
}
##设置不拦截URI
app.zuul.auth.methodGetUrl = \
/authentication/require,\
/app/account/**
app.zuul.auth.methodPostUrl=/authentication/form,\
/login
## 设置oauth2授权认证
app.zuul.oauth.clients[0].clientId = app
## 需要配置一个passwordEncoder我配置的是123456
app.zuul.oauth.clients[0].clientSecret = $2a$10$m9W7aCgZ8HwyMtP/CQY2mecC1k6Zjry28HBimMx2.5SuCJPv08C9y
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@SpringBootApplication
//@EnableDiscoveryClient
//@EnableZuulProxy
@EnableConfigurationProperties(ZuulProperties.class)
public class AppOauthApplicationBootstrap {
public static void main(String[] args) {
SpringApplication.run(AppOauthApplicationBootstrap.class,args);
}
}
###认证服务器配置
@Configuration
@EnableAuthorizationServer
public class AppAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
private final AuthenticationManager authenticationManager;
private final UserDetailsService userDetailsService;
private final ZuulProperties zuulProperties;
private final TokenStore tokenStore ;
@Autowired(required = false)
private JwtAccessTokenConverter jwtAccessTokenConverter;
@Autowired(required = false)
private TokenEnhancer jwtTokenEnhancer;
private final PasswordEncoder passwordEncoder;
@Autowired
public AppAuthorizationServerConfig(AuthenticationManager authenticationManager, UserDetailsService userDetailsService, ZuulProperties zuulProperties, TokenStore tokenStore, PasswordEncoder passwordEncoder) {
this.authenticationManager = authenticationManager;
this.userDetailsService = userDetailsService;
this.zuulProperties = zuulProperties;
this.tokenStore = tokenStore;
this.passwordEncoder = passwordEncoder;
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
InMemoryClientDetailsServiceBuilder builder = clients.inMemory();
OAuth2ClientProperties[] clientProperties = zuulProperties.getOauth().getClients();
if(ArrayUtils.isNotEmpty(zuulProperties.getOauth().getClients())) {
for (OAuth2ClientProperties oAuth2ClientProperties : clientProperties) {
builder.withClient(oAuth2ClientProperties.getClientId())
.secret(oAuth2ClientProperties.getClientSecret())
//token有效时间
.accessTokenValiditySeconds(oAuth2ClientProperties.getAccessTokenValiditySeconds())
//验证模式
.authorizedGrantTypes("password","authorization_code","client_credentials","implicit","refresh_token")
//刷新时间
.refreshTokenValiditySeconds(3600*24*100)
//跳转地址
.redirectUris("ws.28ph.cn")
//权限
.scopes("all");
}
}
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager)
.tokenStore(tokenStore)
.userDetailsService(userDetailsService)
.reuseRefreshTokens(true);
if(jwtAccessTokenConverter != null && jwtTokenEnhancer!=null) {
TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
List<TokenEnhancer> tokenEnhancers = new ArrayList<>();
tokenEnhancers.add(jwtTokenEnhancer);
tokenEnhancers.add(jwtAccessTokenConverter);
enhancerChain.setTokenEnhancers(tokenEnhancers);
endpoints
.tokenEnhancer(enhancerChain)
.accessTokenConverter(jwtAccessTokenConverter);
}
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.allowFormAuthenticationForClients()
.passwordEncoder(passwordEncoder)
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
}
@Configuration
public class TokenStoreConfiger {
@Autowired
private RedisConnectionFactory redisConnectionFactory;
@Bean
@ConditionalOnProperty(prefix = "yichao.secuirty.oauth2",name = "storeType",havingValue = "redis")
public TokenStore redisTokenStore() {
return new RedisTokenStore(redisConnectionFactory);
}
// matchIfMissing = true 代表两种验证token方式 如果没有jwt 那么会自动产生UUID 那种 然后存储
//在redis,所以如果没有jwt配置一定要配置spring-redis-jpa
@Configuration
@ConditionalOnProperty(prefix = "yichao.secuirty.oauth2",name = "storeType",havingValue = "jwt",matchIfMissing = true)
public static class JwtToKenConfiger{
@Autowired
private ZuulProperties zuulProperties;
@Bean
public TokenStore jwtTokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
//加密秘钥
converter.setSigningKey(zuulProperties.getOauth().getoAuth2SigningKey());
return converter;
}
@Bean
@ConditionalOnMissingBean(name = "jwtTokenEnhancer")
public TokenEnhancer jwtTokenEnhancer() {
AppTokenEnhancer appTokenEnhancer = new AppTokenEnhancer();
return appTokenEnhancer;
}
}
}
###JWT配置
public class AppTokenEnhancer implements TokenEnhancer {
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
Map<String, Object> info = new HashMap<>();
info.put("author", "yichao.org");
((DefaultOAuth2AccessToken)accessToken).setAdditionalInformation(info);
return accessToken;
}
}
文章大概就到这里,代码git地址
https://github.com/qq1026290752/app-management/tree/master/app-management-zuul