SpringSecurity 是Spring家族的一員赡矢,是Spring家族提供的安全框架溅潜,提供認(rèn)證和授權(quán)功能肋演,最主要的是它提供了簡(jiǎn)單的使用方式抑诸,同時(shí)又有很高的靈活性,簡(jiǎn)單爹殊,靈活蜕乡,強(qiáng)大。
主要的主要的幾個(gè)配置類
自定義Security的策略
AuthorizationServerConfigurerAdapter
例子如下:
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Override
? ? public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
? ? ? ? endpoints
? ? ? ? ? ? ? ? .authenticationManager(authenticationManager)
? ? ? ? ? ? ? ? .tokenGranter(new CompositeTokenGranter(getTokenGranters(endpoints)))
? ? ? ? ? ? ? ? .userDetailsService(userDetailsService)
? ? ? ? ? ? ? ? .tokenStore(tokenStore());
}
@Override
? ? public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
? ? ? ? //存放到db
? ? ? ? clients.jdbc(dataSource);
//? ? ? ? 存放到內(nèi)存
? ? ? ? clients.inMemory()
? ? ? ? ? ? ? ? .withClient("webapp")
? ? ? ? ? ? ? ? .secret(pass)
? ? ? ? ? ? ? ? .scopes("server")
? ? ? ? ? ? ? ? .authorizedGrantTypes("password", "authorization_code", "refresh_token")
? ? ? ? ? ? ? ? .accessTokenValiditySeconds(24 * 60 * 60) //token有效期
? ? ? ? ? ? ? ? .refreshTokenValiditySeconds(24 * 60 * 60)
? ? ? ? ? ? ? ? .and().withClient("app")
? ? ? ? ? ? ? ? .secret(pass)
? ? ? ? ? ? ? ? .scopes("app")
? ? ? ? ? ? ? ? .authorizedGrantTypes("authorization_code", "refresh_token")
? ? ? ? ? ? ? ? .redirectUris("https://www.baidu.com/");
? ? }
/**
? ? * 填充認(rèn)證方式
? ? * @param endpoints endpoints
? ? * @return list
? ? */
? ? private List<TokenGranter> getTokenGranters(AuthorizationServerEndpointsConfigurer endpoints) {
? ? ? ? AuthorizationServerTokenServices tokenServices = endpoints.getTokenServices();
? ? ? ? ClientDetailsService clientDetailsService = endpoints.getClientDetailsService();
? ? ? ? OAuth2RequestFactory oAuth2RequestFactory = endpoints.getOAuth2RequestFactory();
? ? ? ? AuthorizationCodeServices authorizationCodeServices = endpoints.getAuthorizationCodeServices();
? ? ? ? return new ArrayList<>(Arrays.asList(
? ? ? ? ? ? ? ? new RefreshTokenGranter(tokenServices, clientDetailsService, oAuth2RequestFactory),
? ? ? ? ? ? ? ? new AuthorizationCodeTokenGranter(tokenServices, authorizationCodeServices, clientDetailsService,
? ? ? ? ? ? ? ? ? ? ? ? oAuth2RequestFactory),
? ? ? ? ? ? ? ? new ResourceOwnerPasswordTokenGranter(authenticationManager, endpoints.getTokenServices(),
? ? ? ? ? ? ? ? ? ? ? ? clientDetailsService, oAuth2RequestFactory),
? ? ? ? ? ? ? ? new MyAbstractTokenGranter(authenticationManager, tokenServices, clientDetailsService,
? ? ? ? ? ? ? ? ? ? ? ? oAuth2RequestFactory)));
? ? }
}
默認(rèn)情況下spring?security?oauth?的http配置边灭。
ResourceServerConfigurerAdapter:
例子如下
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
? ? @Override
? ? public void configure(HttpSecurity http) throws Exception {
? ? ? ? http
? ? ? ? ? ? ? ? .csrf().disable()
? ? ? ? ? ? ? ? .exceptionHandling()
? ? ? ? ? ? ? ? .authenticationEntryPoint((request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED))
? ? ? ? ? ? ? ? .and()
? ? ? ? ? ? ? ? .authorizeRequests()
? ? ? ? ? ? ? ? .antMatchers("/index/getUser").permitAll()
? ? ? ? ? ? ? ? .antMatchers("/user/getUserPassword").permitAll()
? ? ? ? ? ? ? ? .anyRequest().authenticated()
? ? ? ? ? ? ? ? .and()
? ? ? ? ? ? ? ? .httpBasic();
? ? }
}
WebSecurityConfigurerAdapter 類是個(gè)適配器, 需要配置的時(shí)候需要我們自己寫個(gè)配置類去繼承,根據(jù)自己的需求去進(jìn)行配置即可WebSecurityConfigurerAdapter的配置攔截要優(yōu)先于ResourceServerConfigurerAdapter异希,優(yōu)先級(jí)高的http配置是可以覆蓋優(yōu)先級(jí)低的配置的。
WebSecurityConfigurerAdapter
例子如下:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
? ? /**
? ? * 自定義實(shí)現(xiàn)用戶信息獲取
? ? *
? ? * @return
? ? */
? ? @Bean
? ? @Override
? ? public UserDetailsService userDetailsService() {
? ? ? ? return new MyUserDetailsServiceImpl();
? ? }
? ? /**
? ? * @param auth
? ? * @throws Exception
? ? */
? ? @Override
? ? protected void configure(AuthenticationManagerBuilder auth) throws Exception {
? ? ? ? auth.userDetailsService(userDetailsService())
? ? ? ? ? ? ? ? .passwordEncoder(passwordEncoder());
? ? }
? ? /**
? ? * @param http
? ? * @throws Exception
? ? */
? ? @Override
? ? protected void configure(HttpSecurity http) throws Exception {
? ? ? ? http.csrf().disable()
? ? ? ? ? ? ? ? .authorizeRequests().anyRequest().authenticated()
? ? ? ? ? ? ? ? .and()
? ? ? ? ? ? ? ? .httpBasic();
? ? }
? ? /**
? ? * 不定義沒有password grant_type
? ? */
? ? @Override
? ? @Bean
? ? public AuthenticationManager authenticationManagerBean() throws Exception {
? ? ? ? return super.authenticationManagerBean();
? ? }
? ? /**
? ? * 密碼解析器
? ? * @return PasswordEncoder
? ? */
? ? @Bean
? ? public PasswordEncoder passwordEncoder() {
? ? ? ? return new BCryptPasswordEncoder();
? ? }
}
繼承了抽象類 AbstractTokenGranter
AbstractTokenGranter
public class MyAbstractTokenGranter extends AbstractTokenGranter {
? ? @Autowired
? ? private UserInfo userInfo;
? ? @Autowired
? ? private RedisUtil redisUtil;
? ? private static final String GRANT_TYPE = "sms_cod";
? ? private final AuthenticationManager authenticationManager;
? ? public MyAbstractTokenGranter(AuthenticationManager authenticationManager,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? AuthorizationServerTokenServices tokenServices,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ClientDetailsService clientDetailsService,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? OAuth2RequestFactory requestFactory) {
? ? ? ? this(authenticationManager, tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);
? ? }
? ? protected MyAbstractTokenGranter(AuthenticationManager authenticationManager,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? AuthorizationServerTokenServices tokenServices,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ClientDetailsService clientDetailsService,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? OAuth2RequestFactory requestFactory, String grantType) {
? ? ? ? super(tokenServices, clientDetailsService, requestFactory, grantType);
? ? ? ? this.authenticationManager = authenticationManager;
? ? }
? ? /**
? ? * 我們拿到的 token 終會(huì)過(guò)期的, 對(duì)應(yīng)于刷新 token模式的 RefreshTokenGranter 則負(fù)責(zé)獲取新的 OAuth2AccessToken绒瘦。
? ? *
? ? * @param client
? ? * @param tokenRequest
? ? * @return
? ? */
? ? @Override
? ? protected OAuth2AccessToken getAccessToken(ClientDetails client, TokenRequest tokenRequest) {
? ? ? ? // 傳入的參數(shù)需要有 refresh_token (DefaultOAuth2AccessToken 中有 refreshToken 字段)
? ? ? ? String refreshToken = tokenRequest.getRequestParameters().get("refresh_token");
? ? ? ? // 調(diào)用 tokenService 的刷新方法得到新的 OAuth2AccessToken
? ? ? ? return getTokenServices().refreshAccessToken(refreshToken, tokenRequest);
? ? }
? ? /**
? ? * 用戶攔截
? ? *
? ? * @param client? ? ? client
? ? * @param tokenRequest 請(qǐng)求的令牌
? ? * @return
? ? */
? ? @Override
? ? protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
? ? ? ? Map<String, String> parameters = new LinkedHashMap<String, String>(tokenRequest.getRequestParameters());
? ? ? ? String username = parameters.get("username");
? ? ? ? String password = parameters.get("password");
? ? ? ? String mobile = parameters.get("mobile");
? ? ? ? //客戶端提交的驗(yàn)證碼
? ? ? ? String smscode = parameters.get("sms_cod");
? ? ? ? String type = parameters.get("type");
? ? ? ? parameters.remove("password");
? ? ? ? //驗(yàn)證用戶狀態(tài)(是否警用等)
//? ? ? ? UserInfo userInfo = new UserInfo();
//? ? ? ? userInfo.setMobile(mobile);
? ? ? ? // 驗(yàn)證驗(yàn)證碼
? ? ? ? //獲取服務(wù)中保存的用戶驗(yàn)證碼
? ? ? ? String smsCheckCode = (String) redisUtil.get(userInfo.getMobile());
? ? ? ? if (StringUtils.isBlank(smsCheckCode)) {
? ? ? ? ? ? throw new InvalidGrantException("用戶沒有發(fā)送驗(yàn)證碼");
? ? ? ? }
? ? ? ? if (!smscode.equals(smsCheckCode)) {
? ? ? ? ? ? throw new InvalidGrantException("驗(yàn)證碼不正確");
? ? ? ? } else {
? ? ? ? ? ? //驗(yàn)證通過(guò)后從緩存中移除驗(yàn)證碼
? ? ? ? ? ? redisUtil.setRemove(userInfo.getMobile(), smsCheckCode);
? ? ? ? }
? ? ? ? if (username.isEmpty()) {
? ? ? ? ? ? throw new InvalidGrantException("用戶不存在");
? ? ? ? }
? ? ? ? Authentication userAuth = new UsernamePasswordAuthenticationToken(username, password);
? ? ? ? ((AbstractAuthenticationToken) userAuth).setDetails(parameters);
? ? ? ? try {
? ? ? ? ? ? userAuth = authenticationManager.authenticate(userAuth);
? ? ? ? } catch (AccountStatusException ase) {
? ? ? ? ? ? //covers expired, locked, disabled cases (mentioned in section 5.2, draft 31)
? ? ? ? ? ? throw new InvalidGrantException(ase.getMessage());
? ? ? ? } catch (BadCredentialsException e) {
? ? ? ? ? ? // If the username/password are wrong the spec says we should send 400/invalid grant
? ? ? ? ? ? throw new InvalidGrantException(e.getMessage());
? ? ? ? }
? ? ? ? if (userAuth == null || !userAuth.isAuthenticated()) {
? ? ? ? ? ? throw new InvalidGrantException("Could not authenticate user: " + username);
? ? ? ? }
? ? ? ? OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest);
? ? ? ? return new OAuth2Authentication(storedOAuth2Request, userAuth);
? ? }
核心依賴配置配置如下:
<dependency>
? ? ? ? ? ? <groupId>org.springframework.security.oauth</groupId>
? ? ? ? ? ? <artifactId>spring-security-oauth2</artifactId>
? ? ? ? ? ? <version>${oauth2.version}</version>
? ? ? ? </dependency>
? ? ? ? <dependency>
? ? ? ? ? ? <groupId>org.springframework.cloud</groupId>
? ? ? ? ? ? <artifactId>spring-cloud-starter-security</artifactId>
? ? ? ? ? ? <exclusions>
? ? ? ? ? ? ? ? <!--舊版本 redis操作有問(wèn)題-->
? ? ? ? ? ? ? ? <exclusion>
? ? ? ? ? ? ? ? ? ? <artifactId>spring-security-oauth2</artifactId>
? ? ? ? ? ? ? ? ? ? <groupId>org.springframework.security.oauth</groupId>
? ? ? ? ? ? ? ? </exclusion>
? ? ? ? ? ? </exclusions>
使用SpringSrcurity+Anut2根據(jù)token實(shí)現(xiàn)用戶密碼登錄
service層
/**
? ? * 根據(jù)用戶名查詢
? ? * @param userName 用戶名
? ? * @return 返回的路徑
? ? */
? ? UserInfo getUserInfoByName(@Param("userName") String userName);
Service層
@Service
public class MyUserDetailsServiceImpl implements UserDetailsService {
? ? @Autowired
? ? public PasswordEncoder passwordEncoder;
? ? @Resource
? ? private UserInfoService userInfoService;
? ? @Resource
? ? private UserInfoMapper userInfoMapper;
? ? @Override
? ? public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
? ? ? ? UserInfo userInfo = userInfoService.getUserInfoByName(username);
? ? ? ? if (userInfo == null){
? ? ? ? ? ? throw new UsernameNotFoundException(username);
? ? ? ? }
? ? ? ? return userInfo;
? ? }
Controlleer層
@RestController
@RequestMapping("/")
public class IndexController {
? ? /**
? ? * user
? ? * @param user user
? ? * @return Principal
? ? */
? ? @GetMapping(value = "/user")
? ? public Principal user(Principal user) {
? ? ? ? return user;
? ? }